package com.fengzhilian.timewheel.wheel;

import com.fengzhilian.timewheel.container.Bucket;
import com.fengzhilian.timewheel.container.DelayQueue;
import com.fengzhilian.timewheel.task.TimedTask;

/**
 * 时间轮基础轮
 * @author 郭智峰
 * @Date 2019年12月25日
 */
public abstract class TimeWheel {

    /**
     * {@value #TIME_WHEEL_TYPE_WEEK} 一周时间范围
     */
    public static  final String TIME_WHEEL_TYPE_WEEK="time_wheel_type_week";
    /**
     * {@value #TIME_WHEEL_TYPE_DAY} 一天时间范围
     */
    public static  final String TIME_WHEEL_TYPE_DAY="time_wheel_type_day";
    /**
     * {@value #TIME_WHEEL_TYPE_MONTH} 一月时间范围
     */
    public static  final String TIME_WHEEL_TYPE_MONTH="time_wheel_type_month";
    /**
     * {@value #TIME_WHEEL_TYPE_YEAR} 一年时间范围
     */
    public static  final String TIME_WHEEL_TYPE_YEAR="time_wheel_type_year";
    /**
     * {@value #TIME_WHEEL_TYPE_SIXTY_YEAR} 一甲子年时间范围
     */
    public static  final String TIME_WHEEL_TYPE_SIXTY_YEAR="time_wheel_type_sixty_year";
    protected long tickMs;
    protected String timeWheelType;
    protected DelayQueue delayQueue;

    /** 时间轮大小 */
    protected int wheelSize;

    /** 时间跨度 */
    protected long interval;

    /** 槽 */
    protected Bucket[] buckets;

    /** 时间轮指针 */
    protected long currentTimestamp;

    /** 上层时间轮 */
    protected volatile TimeWheel overflowWheel;

    /**
     * 获得上一级的时间轮
     * @return
     */
    public abstract  TimeWheel getOverflowWheel();
    /**
     * 添加任务到某个时间轮
     */
    public boolean addTask(TimedTask timedTask) throws Exception {
        long expireTimestamp = timedTask.getExpireTimestamp();
        long delayMs = expireTimestamp - currentTimestamp;
        if (delayMs < tickMs) {// 到期了
            return false;
        } else {

            // 扔进当前时间轮的某个槽中，只有时间【大于某个槽】，才会放进去
            if (delayMs < interval) {
                int bucketIndex = (int) (((delayMs + currentTimestamp) / tickMs) % wheelSize);

                Bucket bucket = buckets[bucketIndex];
                bucket.addTask(timedTask);
            } else {
                // 当maybeInThisBucket大于等于wheelSize时，需要将它扔到上一层的时间轮
                TimeWheel timeWheel = getOverflowWheel();
                if(timeWheel!=null){

                    timeWheel.addTask(timedTask);
                } else {
                    throw new Exception("超过延时容量【className:"+this.getClass().getName()+",interval:"+interval+",wheelSize:"+wheelSize+",tickMs:"+tickMs+"】");
                }
            }
        }
        return true;
    }

    public long getCurrentTimestamp() {
        return currentTimestamp;
    }

    public void setCurrentTimestamp(long currentTimestamp) {
        this.currentTimestamp = currentTimestamp;
    }
}
